﻿///////////////////////////////////////////////////////////////
//                                                           //
// Code from Arcanea Project.                                //
//                                                           //
// Please include this license part to every reproduction    //
//   of code.                                                //
//                                                           //
// This code is under Ms-RL license                          //
//                                                           //
// Please read futher information about the license,         //
//   the project (news and updates) and the                  //
//   contributors on the address :                           //
//     http://www.codeplex.com/Arcanea/                      //
//                                                           //
///////////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;
//using System.Linq;
using System.Text;
using Arcanea.NetworkEngine.Abstract.Engines;
using System.Reflection;
using System.Net.Sockets;
using Arcanea.Mediator.FullClasses;
using Arcanea.Mediator.Toolbox;
using Arcanea.Mediator.BinaryClasses;
using log4net;

namespace Arcanea.NetworkEngine.Abstract
{
    /// <summary>
    /// Interface de l'engine network.
    /// Elle définit le contrat que doit respecter une NetEngine.
    /// </summary>
    public abstract class INetEngine
    {
        protected static readonly ILog logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

        protected ISerialisationEngine _serialisationEngine = null;
        protected abstract ISerialisationEngine SerialisationEngine { get; }

        protected ICompressionEngine _compressionEngine = null;
        protected abstract ICompressionEngine CompressionEngine { get; }

        protected ICryptageEngine _cryptageEngine = null;
        protected abstract ICryptageEngine CryptageEngine { get; }

        protected IFrameEngine _frameEngine = null;
        protected abstract IFrameEngine FrameEngine { get; }

        protected IProtocoleEngine _protocoleEngine = null;
        public abstract IProtocoleEngine ProtocoleEngine { get; }

        /// <summary>
        /// Envoit un objet sur le réseau selon les 
        /// engines spécifiées
        /// </summary>
        /// <param name="obj">Paquet qui doit être envoyé sur le réseau</param>
        public void Send(FullPacket obj)
        {
            byte[] o = SerialisationEngine.Serialise(obj.BinaryFrame);
            if (o == null)
            {
                logger.Error("Impossible de serialiser un parametre");
                return;
            }
            o = CompressionEngine.Compress(o);
            if (o == null)
            {
                logger.Error("Impossible de compresser un parametre");
                return;
            }
            o = CryptageEngine.Crypt(o);
            if (o == null)
            {
                logger.Error("Impossible de crypter un parametre");
                return;
            }
            o = FrameEngine.BuildFrame(o);
            if (o == null)
            {
                logger.Error("Impossible de FrameBuilder un parametre");
                return;
            }
            if (!ProtocoleEngine.Send(o))
            {
                logger.Error("Impossible d'envoyer un parametre");
                return;
            }
            else
                logger.Debug("Parametre envoyé");

        }

        /// <summary>
        /// Recoit un paquet du réseau selon les engines spécifiées
        /// </summary>
        /// <returns>Le FullPacket recu de cette manière</returns>
        public FullPacket Receive()
        {
            byte[] o = FrameEngine.UnbuildFrame(ProtocoleEngine);
            if (o == null)
            {
                logger.Error("Impossible de Unbuilder un parametre");
                return null;
            }
            o = CryptageEngine.Decrypt(o);
            if (o == null)
            {
                logger.Error("Impossible de decrypter un parametre");
                return null;
            }
            o = CompressionEngine.Decompress(o);
            if (o == null)
            {
                logger.Error("Impossible de decompresser un parametre");
                return null;
            }
            object obj = SerialisationEngine.Deserialise(o);
            if (obj == null)
            {
                logger.Error("Impossible de deserialiser un parametre");
                return null;
            }
            else
            {
                logger.Debug("Parametre recu");
                return FullToolbox.Instance.PackBinPacketToFullPacket((BinPacket) obj);
            }
        }

        /// <summary>
        /// Ferme la NetEngine
        /// </summary>
        /// <returns>true si aucun problème sinon false</returns>
        public abstract bool Close();
    }
}
